This invention relates to virtual memory systems and techniques in computer systems.
It is common for a computer processor and associated operating system to have two different levels of resources and protection. One level, referred to as a non-privileged mode or user mode, is used by various operating system components, application programs, and other so-called xe2x80x9cuserxe2x80x9d processes or programs. At this level, an execution thread is prevented by the operating system and by the computer processor from performing certain security-critical operations. The thread is also prevented from directly accessing many system resources. The purpose of the non-privileged execution mode is to isolate a user process as much as possible so that it cannot interfere with other user processes or with operating system functions. While a user process may itself crash, it should not be able to crash other programs or the operating system.
The other level of execution is referred to as privileged mode, system mode, or kernel mode. Critical operating system components are implemented in kernel modexe2x80x94kernel-mode components are responsible for things like virtual memory management, responding to interrupts and exceptions, scheduling execution threads, synchronizing the activities of multiple processors, and other critical or sensitive functions. Such components, which execute from system mode, are generally referred to collectively as xe2x80x9cthe kernel.xe2x80x9d
The kernel is responsible for supervising the virtual memory system in most computer systems. The virtual memory system is largely responsible for isolating processes from each other. With virtual memory, a process is assigned its own virtual address space, which is not available to other processes. Through its virtual memory, a process has a logical view of memory that does not correspond to the actual layout of physical memory. Each time a process uses a virtual memory address, the virtual memory system translates it into a physical address using a virtual-to-physical address mapping contained in some type of look-up structure and address mapping database.
Rather than attempting to maintain a translation or mapping for each possible virtual address, virtual memory systems divide virtual and physical memory into blocks. In many systems, these blocks are fixed in size and referred to as sections or pages. Data structures are typically maintained in physical memory to translate from virtual page addresses to physical page addresses. These data structures often take the form of conversion tables, normally referred to as page tables. A page table is indexed by virtual page address or number, and generally has a number of entries corresponding to pages in the virtual address space. Each entry is a mapping of a specific page number or virtual page address to a physical page address.
FIG. 1 shows a prior art example of a virtual memory system using a page table. A process generates a virtual address 12. The page number portion of the virtual address (usually the uppermost bits) is used to index a page table 13. The page table, in turn, contains a physical address of a location or page in physical memory 14. In practice, a two-level page table scheme is often implemented, using multiple page tables in at least one of the levels.
FIG. 2 shows an additional level of address conversion available in processors such as the Intel 486 and Pentium Pro(copyright) microprocessors. These processors add a segment offset 15 to virtual memory address 12 before indexing the page table. The segment offset can be changed during program execution. In some cases, the segment offset changes automatically during program executionxe2x80x94such as when switching between privileged and non-privileged execution modes. To implement this feature, the microprocessor has sets of offset registers. A designated set is active at each different privilege level of the microprocessor. The different offset registers in each set are used for different types of memory accesses, such as for data memory access and code memory access.
A typical approach to managing computer system memory is to allocate some portion of the memory to the operating system or kernel and another portion for application or user processes. The kernel typically runs in a dedicated or private virtual address space. The kernel or system virtual address space is protected, by processor hardware, from being accessed by any execution thread that is not in the privileged execution mode. Therefore, in practice, the kernel address space consists of a range of virtual addresses that cannot be directly accessed by user processes.
Current micro processors have a 4 gigabyte virtual address space, which is typically divided for use by the kernel and by a user process, respectively. For example, the upper 2 gigabytes of these addresses might be reserved for the kernel, while the lower 2 gigabytes would be available for a user process. Each user process thus has its own 2 gigabyte virtual address space. A user process may conventionally access only the system memory allocated to the user process. The kernel may access both the kernel system memory and the user process system memory.
FIG. 3 shows virtual memory from the view of a user process and from the view of the system or kernel. The user process can use only a range of addresses from 0-2 gigabytes, typically referred to as a user address space. The kernel can access both its private, protected address space at a range of addresses from 2-4 gigabytes (addresses 80000000h to FFFFFFFFh), and the user address space at 0-2 gigabytes (addresses 00000000h to 80000000h).
Note that the kernel effectively has a single address space extending from 0 gigabytes to 4 gigabytes. The user address space appears in or is mapped into the lower 2 gigabytes of this address space, while the kernel executes from the upper 2 gigabytes of this space. The dashed arrow indicates that the kernel address space is mapped to physical memory in such a way that the user address space appears at addresses 00000000h to 80000000h of the kernel address space.
The actual mapping of virtual memory to physical memory is shown in FIG. 4. A user address space 16 (extending from address 00000000h to address 80000000h) is associated with a set of virtual-to-physical mappings 17 (implemented by processor-dependent structures such as page tables and offset registers). These mappings define a region 18 of physical memory for use by a user process.
Similarly, the kernel is located in an address space 19 (extending from address 80000000h to address FFFFFFFFh) that is associated with another set of virtual-to-physical mappings 20. These mappings define a region 21 of physical memory for use by the kernel. Note that the physical address regions are not necessarily contiguous, although they are shown that way in FIG. 4 for purposes of this discussion.
The kernel also has access to an address space 22. This address space is associated with the same virtual-to-physical mappings 17 that are associated with user address space 16, thereby associating physical memory region 18 with address space 22. The result is that user address space 16 (corresponding to physical memory region 18) appears in and can be accessed through address space 22 of the kernel as illustrated in FIG. 3. Thus, the user address space can be described as being mapped into the kernel address space.
When there are a plurality of user processes, each with its own address space, only one of the address spaces is mapped into the kernel address space at any given time. The particular user address space that is mapped into the kernel""s address space depends on the current execution context: if the processor is in the context of a user process 1, the corresponding address space of user process 1 is mapped into the kernel""s address space; if the processor is in the context of a user process 2, the address space of user process 2 is mapped into the kernel""s address space. At each context change, the mapping of the lower 2 gigabytes of the kernel""s memory space is changed to the context of the current user process.
It is often necessary for a user process to invoke system or kernel functions. When a user process calls a system function, the computer processor traps the call and switches the current execution thread from user mode to kernel mode. The kernel takes control of the thread, validates the arguments received from the thread and then executes the designated system function. The operating system switches the thread back to user mode before returning control to the user process. In this way, only system functions are allowed to execute from the privileged kernel mode. This protects the kernel and its data from perusal and modification by user processes.
It is an important benefit for the kernel to be able to access a calling process""s virtual memory spacexe2x80x94it allows a user process to pass data addresses to kernel functions rather than passing data itself. The kernel can use the addresses to read, modify, and write memory in the user process"" virtual address space.
There is, however, an important shortcoming of this virtual memory scheme: it does not allow sharing of memory-resident and position-dependent code between user-mode and kernel-mode threads. To illustrate this, FIG. 5 shows a virtual memory space 23 in the context of a user process A. A potentially is shareable program module such as a DLL (dynamic link library) is loaded in a range of virtual memory addresses within the address space of the user process. The DLL includes a code portion 25 that remains static during program execution, and a data portion 26 that changes during execution of the program. FIG. 5 also shows a kernel 24 residing in the upper 2 gigabytes of virtual memory.
Physical memory is referenced in FIG. 5 by numeral 27. An arrow shows that virtual code portion 25 of the DLL is mapped to a specific portion 28 of physical memory 27. Data portion 26 of the DLL is mapped to a different portion 29 of the physical memory. Kernel 24 is also mapped to portions 30 of physical memory. Note that this example is somewhat simplified, showing each memory component mapped to a contiguous block of physical memory. In practice, the various portions of virtual memory are often mapped to a plurality of discontiguous physical memory pages.
In many operating systems such as the Windows NT(copyright) operating system, executable code is position-dependent. Code must either be loaded at a specific preferred virtual memory address, or be modified to run at some other virtual memory address. Accordingly, in the example of FIG. 5 the shareable DLL is configured to execute only in the prescribed range of addresses at which it has been loaded.
Now suppose that another user process needs to use the same DLL that the first process has already loaded. This can be accomplished as shown in FIG. 5, which shows a second virtual memory space 31 in the context of a user process B. To be shared, the DLL must be positioned in the virtual address space of application program B at the same place as it has already been positioned in the virtual address space of application program A. Such positioning is reflected in FIG. 5. To implement sharing, the virtual memory portion at which code portion 32 has been positioned maps to the same physical memory 28 that is being used by the code portion 25 of application program A.
User process B needs its own copy of data, however. Thus, the virtual memory portion at which data portion 33 has been positioned maps to a different place 34 in physical memory 27 than that used by data portion 26 of application program A.
Now suppose that a kernel-mode thread needs to use the same DLL, but again needs its own copy of the data portion. Since the DLL is position-dependent, the data portion must be located at a specific virtual memory location. However, this location is within the user process address space rather than within the kernel address space. Specifically, the DLL has been configured so that the data portion must be located in the lower part of virtual memoryxe2x80x94the part which is dedicated for use by user processes. While the kernel can access these addresses, doing so for purposes of independently executing the loaded DLL would interfere with the user process. Because of this, it is not possible for the kernel-mode thread to have its own data portion positioned as required by the position-dependent DLLxe2x80x94the data portion needs to be positioned at a specific virtual address range, and in the kernel address space this range maps to a copy of the data portion that already belongs to a user process.
Because of this problem, most operating systems do not allow sharing of executable program modules between kernel-mode threads and user-mode threads. The inventors, however, have discovered a way to allow such sharing while still allowing the kernel to access the full address space of all user processes.
The invention includes a computer system having both privileged and non-privileged modes of execution. In the non-privileged mode, an executing thread has access to a limited user address space. The kernel executes in the privileged mode from its own address space.
The virtual addresses included in the two respective address spaces are not mutually exclusive. Rather, the ranges of addresses in the two virtual address spaces overlap: the user address space includes a shared address range that coincides with an identical shared address range in the kernel address space. Within both the user address space and the kernel address space, this shared range of addresses is designated for shared executable components.
The kernel address space includes the entire user address space. However, the user address space is not mapped directly into the kernel address space. Rather, the user address space is mapped to an offset position within the kernel virtual address space. This moves the shared address range of the user address space so that it does not necessarily map to the same physical address space as the shared address range of the kernel address space.
To allow user processes to pass valid memory pointers to kernel functions, the operating system biases any such arguments received from user processes before using them. The bias is calculated to account for the offset position of the user address space within the kernel address space.
This scheme allows the kernel to access the entire range of valid user addresses, while also allowing executable components to be shared between user-mode threads and kernel-mode threads.